package com.firexxx.vp.domain.vp.fuse;

import com.firexxx.common.domain.AbstractEntity;
import com.firexxx.vp.domain.audio.AudioEntity;
import com.firexxx.vp.domain.mlv.MlvEngineFactory;
import com.firexxx.vp.domain.vp.VoicePrintModel;
import com.firexxx.vp.domain.vp.VoicePrintResourceType;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.Where;

import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @description: TODO
 * @throws:
 * @author: zhuangzhang2
 * @date: 2019/12/19 11:25
 */
@Entity
@Table(name = "fuse_voiceprint")
@DynamicInsert
@DynamicUpdate
@Where(clause = "is_deleted = false")
@Getter
@NoArgsConstructor(access = AccessLevel.PACKAGE)
@Slf4j
public class FuseVoicePrintEntity extends AbstractEntity {

    @NotNull
    @Setter
    @ElementCollection
    @CollectionTable(name = "fuse_audio_id", joinColumns = @JoinColumn(name = "fuse_id"))
    @Column(name = "audio_id")
    private List<String> audioIdList;

    //暂时放这里，但是这些transient的含义应该是内存缓存，所以应该放在查询服务中
    @Transient
    private List<AudioEntity> audioList;

    @NotNull
    @Embedded
    @Setter
    private VoicePrintModel vpModel;

    @NotNull
    @Column(name = "group_id")
    private String groupId;

    public FuseVoicePrintEntity(@NotBlank String groupId, @NotNull List<AudioEntity> audioList) {
        this.audioList = audioList;
        audioIdList = audioList.stream().map(entity -> entity.getAudioId()).collect(Collectors.toList());
        this.groupId = groupId;
    }

    public void fuseVoicePrint(VoicePrintResourceType vpResourceType) throws Throwable {
        fuseVoicePrintModel(vpResourceType);
        vpModel.extractFeature();
    }

    private void fuseVoicePrintModel(VoicePrintResourceType vpResourceType) throws Throwable {
        if (vpModel != null && vpModel.valid()) {
            return;
        }

        refuseVoicePrint(vpResourceType);
    }

    private void refuseVoicePrint(VoicePrintResourceType vpResourceType) throws Throwable {
        Map<String, byte[]> audioContentMap = new HashMap<>();
        for (AudioEntity audioEntity : audioList) {
            audioContentMap.put(audioEntity.getAudioId(), audioEntity.getContent());
        }

        String modelStr = MlvEngineFactory.getInstance(vpResourceType).registerVoicePrint(audioContentMap);
        vpModel = new VoicePrintModel(vpResourceType, modelStr);
    }
}